home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / displytl / xvgif.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  13.9 KB  |  500 lines

  1. /*
  2.  * xvgif.c  -  GIF loading code for 'xv'.  Based strongly on...
  3.  *
  4.  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
  5.  *
  6.  * Copyright (c) 1988, 1989 by Patrick J. Naughton
  7.  *
  8.  * Author: Patrick J. Naughton
  9.  * naughton@wind.sun.com
  10.  *
  11.  * Permission to use, copy, modify, and distribute this software and its
  12.  * documentation for any purpose and without fee is hereby granted,
  13.  * provided that the above copyright notice appear in all copies and that
  14.  * both that copyright notice and this permission notice appear in
  15.  * supporting documentation.
  16.  *
  17.  * This file is provided AS IS with no warranties of any kind.  The author
  18.  * shall have no liability with respect to the infringement of copyrights,
  19.  * trade secrets or any patents by this file or any part thereof.  In no
  20.  * event will the author be liable for any lost revenue or profits or
  21.  * other special, indirect and consequential damages.
  22.  *
  23.  */
  24.  
  25. /*
  26.  * Copyright 1989, 1990 by the University of Pennsylvania
  27.  *
  28.  * Permission to use, copy, and distribute for non-commercial purposes,
  29.  * is hereby granted without fee, providing that the above copyright
  30.  * notice appear in all copies and that both the copyright notice and this
  31.  * permission notice appear in supporting documentation.
  32.  *
  33.  * The software may be modified for your own purposes, but modified versions
  34.  * may not be distributed.
  35.  *
  36.  * This software is provided "as is" without any express or implied warranty.
  37.  */
  38. /* $Header $ */
  39. /* $Log $ */
  40. static char xvgifrcsid[] = "$Header: /Source/Media/collab/DisplayTool/RCS/xvgif.c,v 1.1 92/09/29 01:05:24 drapeau Exp $";
  41.  
  42. #include "xvimage.h"
  43.  
  44. typedef int boolean;
  45.  
  46. #define NEXTBYTE (*ptr++)
  47. #define IMAGESEP 0x2c
  48. #define EXTENSION 0x21
  49. #define INTERLACEMASK 0x40
  50. #define COLORMAPMASK 0x80
  51.  
  52. FILE *fp;
  53.  
  54. int BitOffset = 0,        /* Bit Offset of next code */
  55.     XC = 0, YC = 0,        /* Output X and Y coords of current pixel */
  56.     Pass = 0,            /* Used by output routine if interlaced pic */
  57.     OutCount = 0,        /* Decompressor output 'stack count' */
  58.     RWidth, RHeight,        /* screen dimensions */
  59.     Width, Height,        /* image dimensions */
  60.     LeftOfs, TopOfs,        /* image offset */
  61.     BitsPerPixel,        /* Bits per pixel, read from GIF header */
  62.     BytesPerScanline,        /* bytes per scanline in output raster */
  63.     ColorMapSize,        /* number of colors */
  64.     Background,            /* background color */
  65.     CodeSize,            /* Code size, read from GIF header */
  66.     InitCodeSize,        /* Starting code size, used during Clear */
  67.     Code,            /* Value returned by ReadCode */
  68.     MaxCode,            /* limiting value for current code size */
  69.     ClearCode,            /* GIF clear code */
  70.     EOFCode,            /* GIF end-of-information code */
  71.     CurCode, OldCode, InCode,    /* Decompressor variables */
  72.     FirstFree,            /* First free code, generated per GIF spec */
  73.     FreeCode,            /* Decompressor,next free slot in hash table */
  74.     FinChar,            /* Decompressor variable */
  75.     BitMask,            /* AND mask for data size */
  76.     ReadMask,            /* Code AND mask for current code size */
  77.     Misc;                       /* miscellaneous bits (interlace, local cmap)*/
  78.  
  79.  
  80. boolean Interlace, HasColormap;
  81.  
  82. byte *RawGIF;            /* The heap array to hold it, raw */
  83. byte *Raster;            /* The raster data stream, unblocked */
  84.  
  85.     /* The hash table used by the decompressor */
  86. int Prefix[4096];
  87. int Suffix[4096];
  88.  
  89.     /* An output array used by the decompressor */
  90. int OutCode[1025];
  91.  
  92. char *id = "GIF87a";
  93.  
  94. static int EGApalette[16][3] = {
  95.   {0,0,0},       {0,0,128},     {0,128,0},     {0,128,128}, 
  96.   {128,0,0},     {128,0,128},   {128,128,0},   {200,200,200},
  97.   {100,100,100}, {100,100,255}, {100,255,100}, {100,255,255},
  98.   {255,100,100}, {255,100,255}, {255,255,100}, {255,255,255} };
  99.   
  100.  
  101. static int  ReadCode();
  102. static void DoInterlace();
  103. static int  GifError();
  104.  
  105. int filesize;
  106.  
  107. /*****************************/
  108. int LoadGIF(fname,nc)
  109.   char *fname;
  110.   int   nc;
  111. /*****************************/
  112. {
  113.   register byte  ch, ch1;
  114.   register byte *ptr, *ptr1, *picptr;
  115.   register int   i;
  116.   int            npixels, maxpixels;
  117.  
  118.   /* initialize variables */
  119.   BitOffset = XC = YC = Pass = OutCount = npixels = maxpixels = 0;
  120.   RawGIF = Raster = pic = NULL;
  121.   
  122.   fp = fopen(fname,"r");
  123.   if (!fp) {
  124.     fprintf(stderr,"%s: LoadGIF() - unable to open file '%s'\n",cmd,fname);
  125.     return 1;
  126.   }
  127.   
  128.   /* find the size of the file */
  129.   fseek(fp, 0L, 2);
  130.   filesize = ftell(fp);
  131.   fseek(fp, 0L, 0);
  132.   
  133.   /* the +256's are so we can read truncated GIF files without fear of 
  134.      segmentation violation */
  135.   if (!(ptr = RawGIF = (byte *) malloc(filesize+256)))
  136.     return( GifError("not enough memory to read gif file") );
  137.   
  138.   if (!(Raster = (byte *) malloc(filesize+256)))    
  139.     return( GifError("not enough memory to read gif file") );
  140.   
  141.   if (fread(ptr, filesize, 1, fp) != 1) 
  142.     return( GifError("GIF data read failed") );
  143.   
  144.   if (strncmp(ptr, id, 6)) 
  145.     return( GifError("not a GIF file"));
  146.   
  147.   ptr += 6;
  148.   
  149.   /* Get variables from the GIF screen descriptor */
  150.   
  151.   ch = NEXTBYTE;
  152.   RWidth = ch + 0x100 * NEXTBYTE;    /* screen dimensions... not used. */
  153.   ch = NEXTBYTE;
  154.   RHeight = ch + 0x100 * NEXTBYTE;
  155.   
  156.   ch = NEXTBYTE;
  157.   HasColormap = ((ch & COLORMAPMASK) ? True : False);
  158.   
  159.   BitsPerPixel = (ch & 7) + 1;
  160.   numcols = ColorMapSize = 1 << BitsPerPixel;
  161.   BitMask = ColorMapSize - 1;
  162.   
  163.   Background = NEXTBYTE;        /* background color... not used. */
  164.   
  165.   if (NEXTBYTE)        /* supposed to be NULL */
  166.     return( GifError("corrupt GIF file (screen descriptor)") );
  167.   
  168.   
  169.   /* Read in global colormap. */
  170.   
  171.   if (HasColormap)
  172.     for (i=0; i<ColorMapSize; i++) {
  173.       r[i] = NEXTBYTE;
  174.       g[i] = NEXTBYTE;
  175.       b[i] = NEXTBYTE;
  176.     }
  177.   else {  /* no colormap in GIF file */
  178.     /* put std EGA palette (repeated 16 times) into colormap, for lack of
  179.        anything better to do */
  180.  
  181.     for (i=0; i<256; i++) {
  182.       r[i] = EGApalette[i&15][0];
  183.       g[i] = EGApalette[i&15][1];
  184.       b[i] = EGApalette[i&15][2];
  185.     }
  186.   }
  187.  
  188.  
  189.   while ( (i=NEXTBYTE) == EXTENSION) {  /* parse extension blocks */
  190.     int i, fn, blocksize, aspnum, aspden;
  191.  
  192.     /* read extension block */
  193.     fn = NEXTBYTE;
  194.  
  195.     do {
  196.       i = 0;  blocksize = NEXTBYTE;
  197.       while (i<blocksize) {
  198.     if (fn == 'R' && blocksize == 2) {   /* aspect ratio extension */
  199.       aspnum = NEXTBYTE;  i++;
  200.       aspden = NEXTBYTE;  i++;
  201.       if (aspden>0 && aspnum>0) 
  202.         normaspect = (float) aspnum / (float) aspden;
  203.       else { normaspect = 1.0;  aspnum = aspden = 1; }
  204.  
  205.           /* fprintf(stderr,"aspect extension: %d:%d = %f\n", 
  206.           aspnum, aspden,normaspect); */
  207.     }
  208.     else { NEXTBYTE;  i++; }
  209.       }
  210.     } while (blocksize);
  211.   }
  212.  
  213.  
  214.   /* Check for image seperator */
  215.   if (i != IMAGESEP) 
  216.     return( GifError("corrupt GIF file (no image separator)") );
  217.   
  218.   /* Now read in values from the image descriptor */
  219.   
  220.   ch = NEXTBYTE;
  221.   LeftOfs = ch + 0x100 * NEXTBYTE;
  222.   ch = NEXTBYTE;
  223.   TopOfs = ch + 0x100 * NEXTBYTE;
  224.   ch = NEXTBYTE;
  225.   Width = ch + 0x100 * NEXTBYTE;
  226.   ch = NEXTBYTE;
  227.   Height = ch + 0x100 * NEXTBYTE;
  228.  
  229.   Misc = NEXTBYTE;
  230.   Interlace = ((Misc & INTERLACEMASK) ? True : False);
  231.  
  232.   if (Misc & 0x80) {
  233.     for (i=0; i< 1 << ((Misc&7)+1); i++) {
  234.       r[i] = NEXTBYTE;
  235.       g[i] = NEXTBYTE;
  236.       b[i] = NEXTBYTE;
  237.     }
  238.   }
  239.  
  240.  
  241.   if (!HasColormap && !(Misc&0x80)) {
  242.     /* no global or local colormap */
  243.     printf("No colormap in this GIF file.  Assuming EGA colors.\n");
  244.   }
  245.     
  246.  
  247.   
  248.   /* Start reading the raster data. First we get the intial code size
  249.    * and compute decompressor constant values, based on this code size.
  250.    */
  251.   
  252.   CodeSize = NEXTBYTE;
  253.   ClearCode = (1 << CodeSize);
  254.   EOFCode = ClearCode + 1;
  255.   FreeCode = FirstFree = ClearCode + 2;
  256.   
  257.   /* The GIF spec has it that the code size is the code size used to
  258.    * compute the above values is the code size given in the file, but the
  259.    * code size used in compression/decompression is the code size given in
  260.    * the file plus one. (thus the ++).
  261.    */
  262.   
  263.   CodeSize++;
  264.   InitCodeSize = CodeSize;
  265.   MaxCode = (1 << CodeSize);
  266.   ReadMask = MaxCode - 1;
  267.   
  268.  
  269.  
  270.   /* UNBLOCK:
  271.    * Read the raster data.  Here we just transpose it from the GIF array
  272.    * to the Raster array, turning it from a series of blocks into one long
  273.    * data stream, which makes life much easier for ReadCode().
  274.    */
  275.   
  276.   ptr1 = Raster;
  277.   do {
  278.     ch = ch1 = NEXTBYTE;
  279.     while (ch--) { *ptr1 = NEXTBYTE; ptr1++; }
  280.     if ((ptr - RawGIF) > filesize) {
  281.       printf("This GIF file seems to be truncated.  Winging it.\n");
  282.       break;
  283.     }
  284.   } while(ch1);
  285.   free(RawGIF);     RawGIF = NULL;     /* We're done with the raw data now */
  286.  
  287.  
  288.  
  289.   if (DEBUG) {
  290.     fprintf(stderr,"xv: LoadGIF() - picture is %dx%d, %d bits, %sinterlaced\n",
  291.         Width, Height, BitsPerPixel, Interlace ? "" : "non-");
  292.   }
  293.   
  294.   sprintf(formatStr, "GIF, %d bits per pixel, %sinterlaced.  (%d bytes)",
  295.      BitsPerPixel, Interlace ? "" : "non-", filesize);
  296.  
  297.  
  298.  
  299.   /* Allocate the 'pic' */
  300.   pWIDE = Width;  pHIGH = Height;
  301.   maxpixels = Width*Height;
  302.   picptr = pic = (byte *) malloc(maxpixels);
  303.   if (!pic) 
  304.     return( GifError("not enough memory for 'pic'") );
  305.  
  306.   
  307.   /* Decompress the file, continuing until you see the GIF EOF code.
  308.    * One obvious enhancement is to add checking for corrupt files here.
  309.    */
  310.   
  311.   Code = ReadCode();
  312.   while (Code != EOFCode) {
  313.     /* Clear code sets everything back to its initial value, then reads the
  314.      * immediately subsequent code as uncompressed data.
  315.      */
  316.  
  317.     if (Code == ClearCode) {
  318.       CodeSize = InitCodeSize;
  319.       MaxCode = (1 << CodeSize);
  320.       ReadMask = MaxCode - 1;
  321.       FreeCode = FirstFree;
  322.       Code = ReadCode();
  323.       CurCode = OldCode = Code;
  324.       FinChar = CurCode & BitMask;
  325.       if (!Interlace) *picptr++ = FinChar;
  326.          else DoInterlace(FinChar);
  327.       npixels++;
  328.     }
  329.     else {
  330.       /* If not a clear code, must be data: save same as CurCode and InCode */
  331.  
  332.       /* if we're at maxcode and didn't get a clear, stop loading */
  333.       if (FreeCode>=4096) { /* printf("freecode blew up\n"); */
  334.                 break; }
  335.  
  336.       CurCode = InCode = Code;
  337.       
  338.       /* If greater or equal to FreeCode, not in the hash table yet;
  339.        * repeat the last character decoded
  340.        */
  341.       
  342.       if (CurCode >= FreeCode) {
  343.     CurCode = OldCode;
  344.     if (OutCount > 1024) {  /* printf("outcount1 blew up\n"); */ break; }
  345.     OutCode[OutCount++] = FinChar;
  346.       }
  347.       
  348.       /* Unless this code is raw data, pursue the chain pointed to by CurCode
  349.        * through the hash table to its end; each code in the chain puts its
  350.        * associated output code on the output queue.
  351.        */
  352.       
  353.       while (CurCode > BitMask) {
  354.     if (OutCount > 1024) break;   /* corrupt file */
  355.     OutCode[OutCount++] = Suffix[CurCode];
  356.     CurCode = Prefix[CurCode];
  357.       }
  358.       
  359.       if (OutCount > 1024) { /* printf("outcount blew up\n"); */ break; }
  360.       
  361.       /* The last code in the chain is treated as raw data. */
  362.       
  363.       FinChar = CurCode & BitMask;
  364.       OutCode[OutCount++] = FinChar;
  365.       
  366.       /* Now we put the data out to the Output routine.
  367.        * It's been stacked LIFO, so deal with it that way...
  368.        */
  369.  
  370.       /* safety thing:  prevent exceeding range of 'pic' */
  371.       if (npixels + OutCount > maxpixels) OutCount = maxpixels-npixels;
  372.     
  373.       npixels += OutCount;
  374.       if (!Interlace) for (i=OutCount-1; i>=0; i--) *picptr++ = OutCode[i];
  375.                 else  for (i=OutCount-1; i>=0; i--) DoInterlace(OutCode[i]);
  376.       OutCount = 0;
  377.  
  378.       /* Build the hash table on-the-fly. No table is stored in the file. */
  379.       
  380.       Prefix[FreeCode] = OldCode;
  381.       Suffix[FreeCode] = FinChar;
  382.       OldCode = InCode;
  383.       
  384.       /* Point to the next slot in the table.  If we exceed the current
  385.        * MaxCode value, increment the code size unless it's already 12.  If it
  386.        * is, do nothing: the next code decompressed better be CLEAR
  387.        */
  388.       
  389.       FreeCode++;
  390.       if (FreeCode >= MaxCode) {
  391.     if (CodeSize < 12) {
  392.       CodeSize++;
  393.       MaxCode *= 2;
  394.       ReadMask = (1 << CodeSize) - 1;
  395.     }
  396.       }
  397.     }
  398.     Code = ReadCode();
  399.     if (npixels >= maxpixels) break;
  400.   }
  401.   free(Raster);  Raster = NULL;
  402.   
  403.   if (npixels != maxpixels) {
  404.     printf("This GIF file seems to be truncated.  Winging it.\n");
  405.     memset(pic+npixels, 0, maxpixels-npixels);  /* clear to EOBuffer */
  406.   }
  407.  
  408.   if (fp != stdin) fclose(fp);
  409.  
  410.   return 0;
  411. }
  412.  
  413.  
  414. /* Fetch the next code from the raster data stream.  The codes can be
  415.  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  416.  * maintain our location in the Raster array as a BIT Offset.  We compute
  417.  * the byte Offset into the raster array by dividing this by 8, pick up
  418.  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  419.  * bring the desired code to the bottom, then mask it off and return it. 
  420.  */
  421.  
  422. static int ReadCode()
  423. {
  424.   int RawCode, ByteOffset;
  425.   
  426.   ByteOffset = BitOffset / 8;
  427.   RawCode = Raster[ByteOffset] + (Raster[ByteOffset + 1] << 8);
  428.   if (CodeSize >= 8)
  429.     RawCode += (Raster[ByteOffset + 2] << 16);
  430.   RawCode >>= (BitOffset % 8);
  431.   BitOffset += CodeSize;
  432.  
  433.   return(RawCode & ReadMask);
  434. }
  435.  
  436.  
  437. /***************************/
  438. static void DoInterlace(Index)
  439.      byte Index;
  440. {
  441.   static byte *ptr = NULL;
  442.   static int   oldYC = -1;
  443.   
  444.   if (oldYC != YC) {  ptr = pic + YC * Width;  oldYC = YC; }
  445.   
  446.   if (YC<Height)
  447.     *ptr++ = Index;
  448.   
  449.   /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  450.   
  451.   if (++XC == Width) {
  452.     
  453.     /* deal with the interlace as described in the GIF
  454.      * spec.  Put the decoded scan line out to the screen if we haven't gone
  455.      * past the bottom of it
  456.      */
  457.     
  458.     XC = 0;
  459.     
  460.     switch (Pass) {
  461.     case 0:
  462.       YC += 8;
  463.       if (YC >= Height) { Pass++; YC = 4; }
  464.       break;
  465.       
  466.     case 1:
  467.       YC += 8;
  468.       if (YC >= Height) { Pass++; YC = 2; }
  469.       break;
  470.       
  471.     case 2:
  472.       YC += 4;
  473.       if (YC >= Height) { Pass++; YC = 1; }
  474.       break;
  475.       
  476.     case 3:
  477.       YC += 2;  break;
  478.       
  479.     default:
  480.       break;
  481.     }
  482.   }
  483. }
  484.  
  485.  
  486.       
  487. /*****************************/
  488. static int GifError(st)
  489.      char *st;
  490. {
  491.   fprintf(stderr,"%s: LoadGIF() - %s\n",cmd,st);
  492.   
  493.   if (RawGIF != NULL) free(RawGIF);
  494.   if (Raster != NULL) free(Raster);
  495.   if (pic    != NULL) free(pic);
  496.   
  497.   return -1;
  498. }
  499.  
  500.